import axios from 'axios'
import { createApp } from 'vue'
import { notification } from 'ant-design-vue'
import { useMainStore } from '@/store'
import PartLoading from '@/components/loading/PartLoading.vue'
import type { AxiosError, AxiosInstance } from 'axios'
import type { RequestConfig } from '@/types/services/http'

export default function (_axios: AxiosInstance) {
  /** 使用WeakMap类型的数据 键名所指向的对象可以被垃圾回收 避免dom对象的键名内存泄漏 */
  const loadingDom = new WeakMap()
  /** 添加loading */
  const setLoading = (config: RequestConfig) => {
    //添加按钮的loading
    if (config.loading) {
      config.loading.value = true
    }
    const loadingTarget = config.dom
    if (loadingTarget === undefined) return
    const loadingDomInfo = loadingDom.get(loadingTarget)
    if (loadingDomInfo) {
      loadingDomInfo.count++
    } else {
      const appExample = createApp(PartLoading)
      const loadingExample = appExample.mount(document.createElement(`div`)) as InstanceType<
        typeof PartLoading
      >
      loadingTarget.appendChild(loadingExample.$el)
      loadingExample.show(loadingTarget)
      loadingDom.set(loadingTarget, {
        count: 1, //记录当前dom的loading次数
        appExample,
      })
    }
  }
  /** 删除loading */
  const deleteLoading = (config: RequestConfig) => {
    //关闭组件的loading状态
    if (config.loading) {
      config.loading.value = false
    }
    const loadingTarget = config.dom
    if (loadingTarget === undefined) return
    const loadingDomInfo = loadingDom.get(loadingTarget)
    if (loadingDomInfo) {
      if (--loadingDomInfo.count === 0) {
        loadingDom.delete(loadingTarget)
        loadingDomInfo.appExample.unmount()
      }
    }
  }

  //取消重复请求
  const requestList = new Map()
  const cancelDuplicateRequest = (config: RequestConfig) => {
    if (config.isCancelToken) {
      const CancelToken = axios.CancelToken
      const source = CancelToken.source()
      config.cancelToken = source.token
      const requestUrl = config.url as string
      if (requestList.has(requestUrl)) {
        requestList.get(requestUrl).source.cancel({ config: requestList.get(requestUrl).config })
      } else {
        requestList.set(requestUrl, {})
      }
      requestList.get(requestUrl).source = source
      requestList.get(requestUrl).config = config
    }
  }

  //缓存重复请求
  const requestCached = new Map()
  type SetRequest = (
    callBack: (config: RequestConfig) => Promise<any>,
    config: RequestConfig
  ) => Promise<any>
  const setRequestCached: SetRequest = async (callBack, config) => {
    //通过url和接口传参判断是否为同一个接口
    const key = config.url + JSON.stringify(config.params)
    if (config?.isCached) {
      if (requestCached.has(key)) {
        return requestCached.get(key)
      } else {
        const data = await callBack(config)
        requestCached.set(key, data)
        return data
      }
    } else {
      return callBack(config)
    }
  }

  /** 配置axios的公共函数 */
  const setRequest: SetRequest = async (callBack, config) => {
    return setRequestCached(callBack, setPublicConfig(config))
  }

  /** 设置公共配置处理 */
  const setPublicConfig = (config: RequestConfig): RequestConfig => {
    const { deptInfo } = useMainStore()
    //配置公共参数
    let params = {
      // currentDeptId: deptInfo?.deptId,
      ...config.params,
    }
    if (config.formData) {
      const formData = new FormData()
      for (const key in params) {
        formData.append(key, params[key])
      }
      params = formData
    }
    //配置不同请求方式的不同传参
    if ([`put`, `post`, `delete`, `path`].includes(config.method as string)) {
      config.data = params
      config.params = {}
    } else {
      config.params = params
    }
    //配置公共请求头
    // config.headers = { currentDeptId: deptInfo?.deptId }
    return config
  }

  /**
   * 网络请求错误处理函数
   * @param error 错误对象
   */
  const errorHandler = (error: AxiosError) => {
    if (String(error.code) === `400401`) {
      notification.warning({ message: `长时间未操作，请重新登陆！` })
      // eslint-disable-next-line
      console.log('长时间未操作，请重新登陆！')
      location.href = `/sso/login`
    } else if (String(error.code) === `200401`) {
      notification.warning({ message: `登录异常` })
      // eslint-disable-next-line
      console.log(`登录异常`)
      location.href = `/sso/login`
    } else if (String(error.code) === `500499`) {
      notification.warning({
        message: `参数异常`,
        description: error.message,
      })
    } else if (String(error.code) === `999999`) {
      notification.warning({
        message: error.message ? undefined : `系统异常`,
        description: error.message,
      })
    } else {
      notification.warning({
        message: error.code,
        description: error.message,
      })
    }
    return Promise.reject(error)
  }
  return {
    setRequest,
    setLoading,
    deleteLoading,
    cancelDuplicateRequest,
    errorHandler,
  }
}
